package ru.compft.app.as_db.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import ru.compft.app.as_db.AclPermissionsMatrix;
import ru.compft.app.as_db.business.BusinessFacade;
import ru.compft.common.data.AppAcl;
import ru.compft.common.data.AppPermission;
import ru.compft.common.data.AppRole;
import ru.compft.common.data.AppUser;
import ru.compft.common.exception.PermissionDeniedException;
import ru.compft.web.adapter.AclAdapter;
import ru.compft.web.adapter.PermissionAdapter;
import ru.compft.web.adapter.RoleAdapter;
import ru.compft.web.adapter.UserAdapter;
import ru.compft.web.beans.ErrorBean;
import ru.compft.web.beans.PermissionBean;
import ru.compft.web.beans.RoleBean;
import ru.compft.web.beans.UserBean;

import javax.annotation.Resource;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * User: VVasiliev
 * Date: 14.06.12
 * Time: 13:43
 * Контроллер подсистемы администрирования
 */
@Controller("adminController")
@RequestMapping("/admin")
@Scope("session")
public class AdminController implements Serializable {
    private static final long serialVersionUID = 5789315714056456766L;

    private static final Logger logger = LoggerFactory.getLogger(AdminController.class);

    private static final String DEFAULT_VIEW = "admin";

    @Resource(name = "errorBean")
    private ErrorBean errorBean;

    @Resource(name = "userValidator")
    private Validator userValidator;

    @Resource(name = "roleValidator")
    private Validator roleValidator;

    @Resource(name = "permissionValidator")
    private Validator permissionValidator;

    @Resource(name = "appBusinessDelegate")
    private BusinessFacade appBusinessDelegate;

    @ModelAttribute(ErrorBean.BEAN_NAME)
    public ErrorBean getErrorBean() {
        return errorBean;
    }

    /**
     * Регистрируем конвертер дат
     * Формат дат - 2012-10-29 23:23:21.0
     */
    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setLenient(false);
        webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

    /**
     * Отображение страницы по умолчанию
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public String showDefaultPage() {
        System.out.println("Show default view");

        if (logger.isDebugEnabled()) {
            logger.debug("Show default view - " + DEFAULT_VIEW);
        }

        return DEFAULT_VIEW;
    }

    /**
     * Метод POST без параметров
     *
     * @param model
     * @return
     */
    @RequestMapping(method = RequestMethod.POST)
    public String defaultPost(Model model) {
        return showDefaultPage();
    }

    /**
     * Отображение таблицы пользователей
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, params = {"tab=users"})
    public String showAllUsers(Model model) {
        System.out.println("invoke showAllUsers method");

        try {
            final List<AppUser> appUsers = appBusinessDelegate.showAllUsers();
            model.addAttribute("appUsersList", appUsers);

            return "userTable";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение таблицы ролей
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, params = {"tab=roles"})
    public String showAllRoles(Model model) {
        System.out.println("invoke showAllRoles method");

        try {
            final List<AppRole> appRoles = appBusinessDelegate.showAllRoles();
            model.addAttribute("appRolesList", appRoles);

            return "roleTable";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение таблицы разграничения ролей
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, params = {"tab=permissions"})
    public String showAllPermissions(Model model) {
        System.out.println("invoke showAllPermissions method");

        try {
            final List<AppPermission> appPermissions = appBusinessDelegate.showAllPermissions();
            model.addAttribute("appPermissionsList", appPermissions);

            return "permissionTable";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

//    /**
//     * Отображение таблицы разграничения прав доступа к объектам
//     *
//     * @return
//     */
//    @RequestMapping(method = RequestMethod.GET, params = {"tab=acls"})
//    public String showAllAcls(Model model) {
//        System.out.println("invoke showAllAcls method");
//
//        try {
//            final List<AclEntry> aclEntries = appBusinessDelegate.showAllAcls();
//            model.addAttribute("aclEntries", aclEntries);
//
//            return "aclTable";
//        } catch (PermissionDeniedException e) {
//            // возвращаем страницу PermissionDenied
//            return "permissionDenied";
//        }
//    }

    /**
     * Отображение матрицы разграничения прав доступа к объектам по ролям
     * todo сделать правильно.
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, params = {"tab=aclsRoleMatrix"})
    public String showAclRoleMatrix(Model model) {
        System.out.println("invoke showAclMatrix method");

        try {
            // ищем все объекты (например пользователей)
            final List<AppUser> appUserList = appBusinessDelegate.showAllUsers();
            model.addAttribute("aclEntries", appUserList);

            // ищем все роли
            final List<AppRole> appRoleList = appBusinessDelegate.showAllRoles();
            model.addAttribute("aclRecipients", appRoleList);

            final AclPermissionsMatrix matrix = new AclPermissionsMatrix();
            final String clazz = AppUser.class.getName();
            matrix.setClazz(clazz);

            // получаем все права доступа для данного класса для ролей
            final List<AppAcl> aclPermissionsForRole = appBusinessDelegate.getAclPermissionsForRole(clazz);
            final String[] permissions = AclAdapter.convertAclListToStringArray(aclPermissionsForRole);
            matrix.setPermissions(permissions);

            model.addAttribute("aclPermissionsMatrix", matrix);

            return "aclRoleMatrix";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение матрицы разграничения прав доступа к объектам по ролям
     *
     * @return
     */
    @RequestMapping(value = "/saveAclRoleMatrix", method = RequestMethod.POST)
    public String saveAclRoleMatrix(Model model,
                                    @ModelAttribute("aclPermissionsMatrix") AclPermissionsMatrix matrix) {
        System.out.println("invoke saveAclRoleMatrix method");
        try {
            List<AppAcl> appAclList = AclAdapter.convertPermissionsMatrixToAppAclList(matrix.getPermissions(), matrix.getClazz());
            appBusinessDelegate.saveAclPermissions(appAclList);

            // todo сохранено успешно
            return showAclRoleMatrix(model);
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы настроек системы
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, params = {"tab=settings"})
    public String showSettingsPage(Model model) {
        System.out.println("invoke showSettingsPage method");

//        try {
//            final List<AppPermission> appPermissions = appBusinessDelegate.showAllPermissions();
//            model.addAttribute("appPermissionsList", appPermissions);

        return "settingPage";
//        } catch (PermissionDeniedException e) {
        // возвращаем страницу PermissionDenied
//            return "permissionDenied";
//        }
    }

    /**
     * Отображение страницы "Добавление пользователя"
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String showAddUserPage(Model model) {
        System.out.println("invoke showAddUserPage method.");

        try {
            final boolean canShow = appBusinessDelegate.showAddUserPage();
            System.out.println("canShow " + canShow);

            model.addAttribute("userBean", new UserBean());

            return "addUserPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Редактирование пользователя"
     * Обязательный параметр userId
     * Если параметр userId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/editUser", method = RequestMethod.GET)
    public String showEditUserPage(Model model,
                                   @RequestParam("userId") Long userId) {
        System.out.println("invoke showEditUserPage method. userId = " + userId);
        // проверка, что параметр UserId введен корректно
        if (userId == null) return "permissionDenied";
        try {
            final AppUser editableUser = appBusinessDelegate.showEditUserPage(userId);
            final UserBean userBean = new UserBean();
            UserAdapter.copyToBean(editableUser, userBean);

            model.addAttribute("userBean", userBean);

            return "editUserPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Просмотр карточки пользователя"
     * Обязательный параметр userId
     * Если параметр userId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/viewUser", method = RequestMethod.GET)
    public String showViewUserPage(Model model,
                                   @RequestParam("userId") Long userId) {
        System.out.println("invoke showViewUserPage method. userId = " + userId);
        // проверка, что параметр UserId введен корректно
        if (userId == null) return "permissionDenied";
        try {
            final AppUser user = appBusinessDelegate.showViewUserPage(userId);
            final UserBean userBean = new UserBean();
            UserAdapter.copyToBean(user, userBean);

            model.addAttribute("userBean", userBean);

            return "viewUserPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Удаление пользователя
     * Обязательный параметр userId
     * Если параметр userId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/deleteUser", method = RequestMethod.GET)
    public String deleteUser(Model model,
                             @RequestParam("userId") Long userId) {
        System.out.println("invoke deleteUser method. userId = " + userId);
        // проверка, что параметр UserId введен корректно
        if (userId == null) return "permissionDenied";
        return showAllUsers(model);
    }

    /**
     * Действие по кнопке "Отмена" со страницы CRUD пользователя
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*User", method = RequestMethod.POST, params = {"cancel"})
    public String cancelSaveUser(Model model) {
        System.out.println("invoke cancelSaveUser method. ");

        return showAllUsers(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Закрыть" со страницы карточки пользователя
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*User", method = RequestMethod.POST, params = {"close"})
    public String closeViewUser(Model model) {
        System.out.println("invoke closeViewUser method. ");

        return showAllUsers(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Сохранить"
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*User", method = RequestMethod.POST, params = {"save"})
    public String saveUser(Model model,
                           @RequestParam("save") String save,
                           @ModelAttribute("userBean") UserBean newUser,
                           BindingResult result) {
        System.out.println("invoke saveUser method. save = " + save);

        // валидация
        userValidator.validate(newUser, result);

        // нет ошибок валидации - идем дальше
        if (!result.hasErrors()) {
            try {
                final AppUser appUser = appBusinessDelegate.saveUser(UserAdapter.convertToDataObject(newUser));
                System.out.println("saved " + appUser);

                return showAllUsers(model);
//            return "forward:/admin.do?tab=users";
            } catch (PermissionDeniedException e) {
                // возвращаем страницу PermissionDenied
                return "permissionDenied";
            }
        }
        return newUser.getId() != null ? "editUserPage" : "addUserPage";
    }

    /**
     * Отображение страницы "Добавление роли"
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/addRole", method = RequestMethod.GET)
    public String showAddRolePage(Model model) {
        System.out.println("invoke showAddRolePage method.");

        try {
            final boolean canShow = appBusinessDelegate.showAddRolePage();
            System.out.println("canShow " + canShow);

            model.addAttribute("roleBean", new RoleBean());

            return "addRolePage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Редактирование роли"
     * Обязательный параметр roleId
     * Если параметр roleId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/editRole", method = RequestMethod.GET)
    public String showEditRolePage(Model model,
                                   @RequestParam("roleId") Long roleId) {
        System.out.println("invoke showEditRolePage method. roleId = " + roleId);
        // проверка, что параметр roleId введен корректно
        if (roleId == null) return "permissionDenied";
        try {
            final AppRole editableRole = appBusinessDelegate.showEditRolePage(roleId);
            final RoleBean roleBean = new RoleBean();
            RoleAdapter.copyToBean(editableRole, roleBean);

            model.addAttribute("roleBean", roleBean);

            return "editRolePage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Просмотр карточки роли"
     * Обязательный параметр roleId
     * Если параметр roleId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/viewRole", method = RequestMethod.GET)
    public String showViewRolePage(Model model,
                                   @RequestParam("roleId") Long roleId) {
        System.out.println("invoke showViewRolePage method. roleId = " + roleId);
        // проверка, что параметр roleId введен корректно
        if (roleId == null) return "permissionDenied";
        try {
            final AppRole appRole = appBusinessDelegate.showViewRolePage(roleId);
            final RoleBean roleBean = new RoleBean();
            RoleAdapter.copyToBean(appRole, roleBean);

            model.addAttribute("roleBean", roleBean);

            return "viewRolePage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Удаление роли
     * Обязательный параметр roleId
     * Если параметр roleId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/deleteRole", method = RequestMethod.GET)
    public String deleteRole(Model model,
                             @RequestParam("roleId") Long roleId) {
        System.out.println("invoke deleteRole method. roleId = " + roleId);
        // проверка, что параметр roleId введен корректно
        if (roleId == null) return "permissionDenied";
        return showAllRoles(model);
    }

    /**
     * Действие по кнопке "Отмена" со страницы CRUD роли
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Role", method = RequestMethod.POST, params = {"cancel"})
    public String cancelSaveRole(Model model) {
        System.out.println("invoke cancelSaveRole method. ");

        return showAllRoles(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Закрыть" со страницы карточки роли
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Role", method = RequestMethod.POST, params = {"close"})
    public String closeViewRole(Model model) {
        System.out.println("invoke closeViewRole method. ");

        return showAllRoles(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Сохранить" со страницы CRUD роли
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Role", method = RequestMethod.POST, params = {"save"})
    public String saveRole(Model model,
                           @RequestParam("save") String save,
                           @ModelAttribute("roleBean") RoleBean newRole,
                           BindingResult result) {
        System.out.println("invoke saveRole method. save = " + save);
        // валидация
        roleValidator.validate(newRole, result);

        // нет ошибок валидации - идем дальше
        if (!result.hasErrors()) {
            try {
                final AppRole saved = appBusinessDelegate.saveRole(RoleAdapter.convertToDataObject(newRole));
                System.out.println("saved " + saved);

                return showAllRoles(model);
//            return "forward:/admin.do?tab=users";
            } catch (PermissionDeniedException e) {
                // возвращаем страницу PermissionDenied
                return "permissionDenied";
            }
        }
        return newRole.getId() != null ? "editRolePage" : "addRolePage";
    }

    /**
     * Отображение страницы "Добавление права доступа"
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/addPermission", method = RequestMethod.GET)
    public String showAddPermissionPage(Model model) {
        System.out.println("invoke showAddPermissionPage method.");

        try {
            final boolean canShow = appBusinessDelegate.showAddPermissionPage();
            System.out.println("canShow " + canShow);

            model.addAttribute("permissionBean", new PermissionBean());

            return "addPermissionPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Редактирование права доступа"
     * Обязательный параметр permissionId
     * Если параметр permissionId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/editPermission", method = RequestMethod.GET)
    public String showEditPermissionPage(Model model,
                                         @RequestParam("permissionId") Long permissionId) {
        System.out.println("invoke showEditPermissionPage method. permissionId = " + permissionId);
        // проверка, что параметр permissionId введен корректно
        if (permissionId == null) return "permissionDenied";
        try {
            final AppPermission editablePermission = appBusinessDelegate.showEditPermissionPage(permissionId);
            final PermissionBean permissionBean = new PermissionBean();
            PermissionAdapter.copyToBean(editablePermission, permissionBean);

            model.addAttribute("permissionBean", permissionBean);

            return "editPermissionPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Отображение страницы "Просмотр карточки права доступа"
     * Обязательный параметр permissionId
     * Если параметр permissionId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/viewPermission", method = RequestMethod.GET)
    public String showViewPermissionPage(Model model,
                                         @RequestParam("permissionId") Long permissionId) {
        System.out.println("invoke showViewPermissionPage method. permissionId = " + permissionId);
        // проверка, что параметр permissionId введен корректно
        if (permissionId == null) return "permissionDenied";
        try {
            final AppPermission appPermission = appBusinessDelegate.showViewPermissionPage(permissionId);
            final PermissionBean permissionBean = new PermissionBean();
            PermissionAdapter.copyToBean(appPermission, permissionBean);

            model.addAttribute("permissionBean", permissionBean);

            return "viewPermissionPage";
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
    }

    /**
     * Удаление права доступа
     * Обязательный параметр permissionId
     * Если параметр permissionId отсутствут - бросим ошибку
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/deletePermission", method = RequestMethod.GET)
    public String deletePermission(Model model,
                                   @RequestParam("permissionId") Long permissionId) {
        System.out.println("invoke deletePermission method. permissionId = " + permissionId);
        // проверка, что параметр permissionId введен корректно
        if (permissionId == null) return "permissionDenied";
        return showAllPermissions(model);
    }

    /**
     * Действие по кнопке "Отмена" со страницы CRUD права доступа
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Permission", method = RequestMethod.POST, params = {"cancel"})
    public String cancelSavePermission(Model model) {
        System.out.println("invoke cancelSavePermission method. ");

        return showAllPermissions(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Закрыть" со страницы карточки права доступа
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Permission", method = RequestMethod.POST, params = {"close"})
    public String closeViewPermission(Model model) {
        System.out.println("invoke closeViewPermission method. ");

        return showAllPermissions(model);
//        return "redirect:/admin.do?tab=users";
    }

    /**
     * Действие по кнопке "Сохранить" со страницы CRUD права доступа
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/*Permission", method = RequestMethod.POST, params = {"save"})
    public String savePermission(Model model,
                                 @RequestParam("save") String save,
                                 @ModelAttribute("permissionBean") PermissionBean newPermission,
                                 BindingResult result) {
        System.out.println("invoke savePermission method. save = " + save);
        // валидация
        permissionValidator.validate(newPermission, result);

        // нет ошибок валидации - идем дальше
        if (!result.hasErrors()) {
            try {
                final boolean saved = appBusinessDelegate.savePermission(PermissionAdapter.convertToDataObject(newPermission));
                System.out.println("saved " + saved);

                return showAllPermissions(model);
//            return "forward:/admin.do?tab=users";
            } catch (PermissionDeniedException e) {
                // возвращаем страницу PermissionDenied
                return "permissionDenied";
            }
        }
        return newPermission.getId() != null ? "editPermissionPage" : "addPermissionPage";
    }

    /**
     * Действие по кнопке "Закрыть" со страницы карточки права доступа
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/clearCache", method = RequestMethod.POST)
    public String clearCache(Model model) {
        System.out.println("invoke clearCache method. ");
        try {
            appBusinessDelegate.clearCache();
        } catch (PermissionDeniedException e) {
            // возвращаем страницу PermissionDenied
            return "permissionDenied";
        }
        return showSettingsPage(model);
//        return "redirect:/admin.do?tab=users";
    }
}
